﻿/// <reference path="../Libraries/jasmine/jasmine.d.ts" />
/// <reference path="../Jasmine.Matchers.ts" />
/// <reference path="../Jasmine.Matchers.obsolete.ts" />

describe('ExtSpec.Jasmine.Matchers', function () {
    'use strict';

    var ejm = ExtSpec.Jasmine.Matchers;

    // Broken by TypeScript 0.9.0 - re-enable after upgrade
    xdescribe('toHaveBoundEvent', function () {
        it('should match and fail string binding against an expected string', function () {
            var addListener = jasmine.createSpy('addListener'),
                expectation = {
                    actual: addListener,
                    isNot: true
                },
                actual: boolean;

            addListener({
                click: 'onSomethingClick'
            });

            actual = ejm.toHaveBoundEvent.call(expectation, 'click', 'onSomethingClick');

            expect(actual).not.toBe(false);
        });
    });

    describe('toHaveAddedListener', function () {
        var addListener: jasmine.Spy,
            expectation: {
                actual: any;
                isNot: boolean;
            };

        beforeEach(function () {
            addListener = jasmine.createSpy('addListener');
            expectation = {
                actual: addListener,
                isNot: false
            };
        });

        it('should return true using a spy invoked with a matching event name', function () {
            addListener('nounverb');

            var actual = ejm.toHaveAddedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked with a matching event config', function () {
            addListener({
                nounverb: null
            });

            var actual = ejm.toHaveAddedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked three times', function () {
            addListener({
                beforenounverb: null
            });

            addListener('nounverb');

            addListener({
                afternounverb: null
            });

            var actual = ejm.toHaveAddedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should throw when actual is not a spy', function () {
            expectation.actual = true;

            expect(function () {
                ejm.toHaveAddedListener.call(expectation, 'nounverb');
            }).toThrow('Expected true to be a spy.');
        });

        it('should return true given an expected config object', function () {
            addListener({
                afternounverb: null
            });

            var actual = ejm.toHaveAddedListener.call(expectation, {
                    event: 'afternounverb',
                    listener: null
                });

            expect(actual).toBeTruthy();
        });

        it('should return false given a config object with mismatched handler', function () {
            addListener({
                afternounverb: 'right'
            });

            var actual = ejm.toHaveAddedListener.call(expectation, {
                    event: 'afternounverb',
                    listener: 'wrong'
                });

            expect(actual).toBeFalsy();
        });

        it('should return true given a config object with matching handler', function () {
            addListener({
                afternounverb: {
                    fn: 'handler'
                }
            });

            var actual = ejm.toHaveAddedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'handler'
            });

            expect(actual).toBeTruthy();
        });
    });

    describe('toHaveRemovedListener', function () {
        var removeListener,
            expectation;

        beforeEach(function () {
            removeListener = jasmine.createSpy('removeListener');
            expectation = {
                actual: removeListener,
                isNot: false
            };
        });

        it('should return true using a spy invoked with a matching event name', function () {
            removeListener('nounverb');

            var actual = ejm.toHaveRemovedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked with a matching event config', function () {
            removeListener({
                nounverb: null
            });

            var actual = ejm.toHaveRemovedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked three times', function () {
            removeListener({
                beforenounverb: null
            });

            removeListener('nounverb');

            removeListener({
                afternounverb: null
            });

            var actual = ejm.toHaveRemovedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should throw when actual is not a spy', function () {
            expectation.actual = true;

            expect(function () {
                ejm.toHaveRemovedListener.call(expectation, 'nounverb');
            }).toThrow('Expected true to be a spy.');
        });

        it('should return true given an expected config object', function () {
            removeListener({
                afternounverb: null
            });

            var actual = ejm.toHaveRemovedListener.call(expectation, {
                event: 'afternounverb',
                listener: null
            });

            expect(actual).toBeTruthy();
        });

        it('should return false given a config object with mismatched handler', function () {
            removeListener({
                afternounverb: 'right'
            });

            var actual = ejm.toHaveRemovedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'wrong'
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given a config object with matching handler', function () {
            removeListener({
                afternounverb: {
                    fn: 'handler'
                }
            });

            var actual = ejm.toHaveRemovedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'handler'
            });

            expect(actual).toBeTruthy();
        });
    });

    describe('toHaveAddedManagedListener', function () {
        var addManagedListener,
            expectation,
            target = {};

        beforeEach(function () {
            addManagedListener = jasmine.createSpy('addManagedListener');
            expectation = {
                actual: addManagedListener,
                isNot: false
            };
        });

        it('should return true using a spy invoked with a matching event name', function () {
            addManagedListener(target, 'nounverb');

            var actual = ejm.toHaveAddedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked with a matching event config', function () {
            addManagedListener(target, {
                nounverb: null
            });

            var actual = ejm.toHaveAddedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked three times', function () {
            addManagedListener(target, {
                beforenounverb: null
            });

            addManagedListener(target, 'nounverb');

            addManagedListener(target, {
                afternounverb: null
            });

            var actual = ejm.toHaveAddedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should throw when actual is not a spy', function () {
            expectation.actual = true;

            expect(function () {
                ejm.toHaveAddedManagedListener.call(expectation, 'nounverb');
            }).toThrow('Expected true to be a spy.');
        });

        it('should return true given an expected config object', function () {
            addManagedListener(target, {
                afternounverb: null
            });

            var actual = ejm.toHaveAddedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: null
            });

            expect(actual).toBeTruthy();
        });

        it('should return false given a config object with mismatched handler', function () {
            addManagedListener(target, {
                afternounverb: 'right'
            });

            var actual = ejm.toHaveAddedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'wrong'
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given a config object with matching handler', function () {
            addManagedListener(target, {
                afternounverb: {
                    fn: 'handler'
                }
            });

            var actual = ejm.toHaveAddedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'handler'
            });

            expect(actual).toBeTruthy();
        });
    });

    describe('toHaveRemovedManagedListener', function () {
        var removeManagedListener,
            expectation,
            target = {};

        beforeEach(function () {
            removeManagedListener = jasmine.createSpy('removeManagedListener');
            expectation = {
                actual: removeManagedListener,
                isNot: false
            };
        });

        it('should return true using a spy invoked with a matching event name', function () {
            removeManagedListener(target, 'nounverb');

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked with a matching event config', function () {
            removeManagedListener(target, {
                nounverb: null
            });

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should return true using a spy invoked three times', function () {
            removeManagedListener(target, {
                beforenounverb: null
            });

            removeManagedListener(target, 'nounverb');

            removeManagedListener(target, {
                afternounverb: null
            });

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, 'nounverb');

            expect(actual).toBeTruthy();
        });

        it('should throw when actual is not a spy', function () {
            expectation.actual = true;

            expect(function () {
                ejm.toHaveRemovedManagedListener.call(expectation, 'nounverb');
            }).toThrow('Expected true to be a spy.');
        });

        it('should return true given an expected config object', function () {
            removeManagedListener(target, {
                afternounverb: null
            });

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: null
            });

            expect(actual).toBeTruthy();
        });

        it('should return false given a config object with mismatched handler', function () {
            removeManagedListener(target, {
                afternounverb: 'right'
            });

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'wrong'
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given a config object with matching handler', function () {
            removeManagedListener(target, {
                afternounverb: {
                    fn: 'handler'
                }
            });

            var actual = ejm.toHaveRemovedManagedListener.call(expectation, {
                event: 'afternounverb',
                listener: 'handler'
            });

            expect(actual).toBeTruthy();
        });
    });

    describe('toHaveControlled', function () {
        var control: (selector: any, config?: any) => void,
            onClick = function () { },
            expectation: {
                actual: (selector: any, config?: any) => void;
                isNot: boolean;
            };

        beforeEach(function () {
            control = jasmine.createSpy('control');
            control({
                'selector1': {
                    click: onClick
                }
            });
            control('selector2', {
                click: onClick
            });
            expectation = {
                actual: control,
                isNot: false
            };
        });

        it('should throw when actual is not a spy', function () {
            expectation.actual = undefined;

            expect(function () {
                ejm.toHaveControlled.call(expectation, 'nounverb');
            }).toThrow('Expected undefined to be a spy.');
        });

        it('should return true given a matching event name', function () {
            var actual = ejm.toHaveControlled.call(expectation, 'click');

            expect(actual).toBeTruthy();
        });

        it('should return false given a mismatched event name', function () {
            var actual = ejm.toHaveControlled.call(expectation, 'clickz');

            expect(actual).toBeFalsy();
        });

        it('should return false given a matching event name and mismatched selector', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                selector: 'selectorz'
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given a matching event name and selector', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                selector: 'selector1'
            });

            expect(actual).toBeTruthy();
        });

        it('should return false given a matching event name and mismatched listener', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                listener: function () { }
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given a matching event name and listener', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                listener: onClick
            });

            expect(actual).toBeTruthy();
        });

        it('should return true given a matching event name, selector and listener', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                selector: 'selector1',
                listener: onClick
            });

            expect(actual).toBeTruthy();
        });

        it('should return true given matching event name from second, non object call', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                selector: 'selector2'
            });

            expect(actual).toBeTruthy();
        });

        it('should return false given mismatched event name from second, non object call', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'load',
                selector: 'selector2'
            });

            expect(actual).toBeFalsy();
        });

        it('should return true given matching event name and regular expression selector', function () {
            var actual = ejm.toHaveControlled.call(expectation, {
                event: 'click',
                selector: /lector2/
            });

            expect(actual).toBeTruthy();
        });
    });
});